package ss.pku.jsa.type.inference;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.jdt.core.dom.ITypeBinding;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class TypeKey extends JqualKey implements Serializable, Comparable {
	private static final long serialVersionUID = 1L;
	public String typeString;
	int d;
	public String name;
	static Map<Key, TypeKey> cache = new HashMap();

	public static void debugCache() {
		JqualPlugin.out
				.println("-----------------------------------------------------------");
		JqualPlugin.out.println(cache);
		JqualPlugin.out
				.println("-----------------------------------------------------------");
	}

	public static TypeKey getTypeKey(ITypeBinding t) {
		Key k = new Key(t.getKey(), t.getDimensions());
		TypeKey ret = (TypeKey) cache.get(k);
		if (ret == null) {
			ret = new TypeKey(t);
			cache.put(k, ret);
		}
		return ret;
	}

	public static TypeKey getTypeKey(String tkey, int d, String name) {
		Key k = new Key(tkey, d);
		TypeKey ret = (TypeKey) cache.get(k);
		if (ret == null) {
			ret = new TypeKey(tkey, d, name);
			cache.put(k, ret);
		}

		return ret;
	}

	private TypeKey(ITypeBinding t) {
		t.getDimensions();
		this.typeString = t.getKey();
		this.name = t.getQualifiedName();
		if (this.name.length() == 0) {
			this.name = this.typeString;
		}
	}

	private TypeKey(String key, int d, String name) {
		this.typeString = key;
		this.name = name;
		this.d = d;
	}

	public static TypeKey getKeyForArrayOf(TypeKey t) {
		return getTypeKey(t.typeString, t.d + 1, t.name);
	}

	public int compareTo(Object o) {
		return toString().compareTo(o.toString());
	}

	public String toString() {
		String ret = this.name;
		for (int i = this.d; i > 0; i--) {
			ret = ret + "[]";
		}
		return ret;
	}

	public String baseTypeToString() {
		return this.name;
	}

	private static class Key {
		String keyString;
		int d;

		public Key(String key, int d) {
			this.keyString = key;
			this.d = d;
		}

		public int hashCode() {
			int result = 1;
			result = 31 * result + this.d;
			result = 31 * result
					+ (this.keyString == null ? 0 : this.keyString.hashCode());
			return result;
		}

		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Key other = (Key) obj;
			if (this.d != other.d)
				return false;
			if (this.keyString == null) {
				if (other.keyString != null)
					return false;
			} else if (!this.keyString.equals(other.keyString))
				return false;
			return true;
		}
	}
}
